package com.naicha.wechat.wechat.controller;

import com.naicha.wechat.wechat.businessservice.WeChatBusinessService;
import com.naicha.wechat.wechat.enums.WeChatRegisterCode;
import com.naicha.wechat.wechat.factory.DynamicMessageFactory;
import com.naicha.wechat.wechat.factory.model.TextMessage;
import com.naicha.wechat.wechat.model.*;
import com.naicha.wechat.wechat.utils.CommonFunction;
import com.naicha.wechat.wechat.utils.GsonUtil;
import com.naicha.wechat.wechat.utils.HttpRequestUtils;
import lombok.extern.slf4j.Slf4j;
import org.apache.http.HttpStatus;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.util.StringUtils;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import java.net.URLEncoder;
import java.util.HashMap;
import java.util.Map;

/**
 * @author NaiCha
 * @date 2019/4/29 10:37
 * @description 微信工具控制器
 **/
@Slf4j
@RestController
@RequestMapping(value = "/wc/util")
public class WeChatUtilController {

    @Autowired
    private WeChatBusinessService weChatBusinessService;

    /**
     * 消息加密密钥
     */
    private static final String ENCODING_AES_KEY = "7jWzQshX8Ap2ZF1E5cidZIf45KJx8xfi2fvW98CEANo";

    /**
     * 开发者ID(测试)
     */
    private static final String APP_ID = "wx7102bcc0b2fb1a92";

    /**
     * 开发者密码(测试)
     */
    private static final String APP_SECRET = "58285d8e12af0356c7323794a80b7427";

    /**
     * 获取access_token(有效期2小时)
     * @return
     */
    @RequestMapping(value = "/getAccessToken",method = RequestMethod.GET)
    public String getAccessToken(HttpServletRequest request){
        //首先从缓存服务器获取access_token 没有请求微信获取(暂不实现，暂存session)
        HttpSession session = request.getSession();
        Object access_token = session.getAttribute("access_token");
        if(access_token == null){
            String getAccessTokenURL = "https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=" + APP_ID + "&secret=" + APP_SECRET;
            String result = HttpRequestUtils.send_get(getAccessTokenURL, null);
            if (!StringUtils.isEmpty(result)){
                Map<String, Object> resultMap = GsonUtil.fromJsonToMap(result);
                access_token = resultMap.get("access_token");
                if(access_token == null){
                    return result;
                }else {
                    //存储access_token
                    session.setMaxInactiveInterval(7200);
                    session.setAttribute("access_token",access_token);
                    return access_token.toString();
                }
            }else {
                return null;
            }
        }else{
            return access_token.toString();
        }
    }


    /*****************************************************************************微信二维码登陆分割线*********************************************************************************************************/

    /**
     * 第一步：获取请求CODE
     */
    @RequestMapping(value = "/getLoinCode",method = RequestMethod.GET)
    public String getLoinCode(){
        //回调网址 域名要与审核时填写的授权域名一致且使用urlEncode对链接进行处理
        String backUrl = "";
        String redirect_uri = URLEncoder.encode(backUrl);
        //获取请求code
        String requestUrl = "https://open.weixin.qq.com/connect/qrconnect?"
                + "appid=" + APP_ID
                + "&redirect_uri=" + redirect_uri
                + "&response_type=code"
                + "&scope=snsapi_login"
                + "&state=STATE#wechat_redirect";
        log.info("获取CODE:URL-:" + requestUrl);
        return requestUrl;
    }

    /**
     * 登陆授权回调-通过code获取access_token
     * @param request
     * @param response
     */
    @RequestMapping(value = "callBack.do",method = RequestMethod.GET)
    public void callBack(HttpServletRequest request, HttpServletResponse response){
        ReturnData returnData = new ReturnData();
        //用户允许授权后，将会重定向到redirect_uri的网址上，并且带上code和state参数
        //若用户禁止授权，则重定向后不会带上code参数，仅会带上state参数
        String code = request.getParameter("code");
        if (!StringUtils.isEmpty(code)){
            AccessToken accessToken = GsonUtil.fromJsonToObject(getAccessToken(code), AccessToken.class);
            String access_token = accessToken.getAccess_token();
            if(!StringUtils.isEmpty(access_token)){
                String openid = accessToken.getOpenid();
                String refresh_token = accessToken.getRefresh_token();
                //检查access_token有效性
                ErrorModel errorModel = GsonUtil.fromJsonToObject(authAccessToken(access_token, openid), ErrorModel.class);
                if(errorModel.getErrcode() != 0){
                    //刷新或续期access_token使用
                    accessToken = GsonUtil.fromJsonToObject(refreshToken(refresh_token),AccessToken.class);
                    access_token = accessToken.getAccess_token();
                }
                String userInfo = getWeChatUserInfo(access_token, openid);
                WeChatUserInfo weChatUserInfo = GsonUtil.fromJsonToObject(userInfo, WeChatUserInfo.class);
                if(weChatUserInfo != null){
                    //判断用户是第一次登陆(第一次登陆需要用户绑定手机号)
                    //根据openid & unionid 查询当前用户是否注册
                    boolean flag = weChatBusinessService.getUserInfo(openid,weChatUserInfo.getUnionid()) == null;
                    if(flag){
                        //未注册需要前端跳转填写手机号页面进行注册
                        //TODO 使用unionid做key 将微信用户的个人信息放入缓存 等用户填写手机号完毕后一起入库 伪代码实现
                        Map<String,Object> cacheMap = new HashMap<>();
                        cacheMap.put(weChatUserInfo.getUnionid(),weChatUserInfo);
                        //将unionid返回前端
                        returnData = new ReturnData(true, WeChatRegisterCode.UN_REGISTER.getPrefix(), WeChatRegisterCode.UN_REGISTER.getDisplay(),weChatUserInfo.getUnionid());
                    }else{
                        //跳转首页
                        returnData = new ReturnData(true, WeChatRegisterCode.REGISTERED.getPrefix(), WeChatRegisterCode.REGISTERED.getDisplay(),weChatUserInfo.getUnionid());
                    }
                }else{
                    //获取用户信息失败
                    log.error("获取微信用户信息失败！");
                    returnData = new ReturnData(false, HttpStatus.SC_INTERNAL_SERVER_ERROR,"获取微信用户信息失败！",null);
                }
            }
        }else{
            log.info("获取Code失败");
            returnData = new ReturnData(false, HttpStatus.SC_INTERNAL_SERVER_ERROR,"获取Code失败！",null);
        }
        CommonFunction.responseWrite(response,returnData,null);
    }

    /**
     * 通过code获取access_token
     * success return
     * {
     * "access_token":"ACCESS_TOKEN",
     * "expires_in":7200,
     * "refresh_token":"REFRESH_TOKEN",
     * "openid":"OPENID",
     * "scope":"SCOPE"
     * }
     * error return
     * {
     * "errcode":40029,"errmsg":"invalid code"
     * }
     * @param code 第一步获取的code参数
     * @return
     */
    public String getAccessToken(String code){
        String requestUrl = "https://api.weixin.qq.com/sns/oauth2/access_token?"
                + "appid=" + APP_ID
                + "&secret=" + APP_SECRET
                + "&code=" + code
                + "&grant_type=authorization_code";
        log.info("回调获取access_token:URL-" + requestUrl);
        return HttpRequestUtils.send_get(requestUrl, null);
    }


    /**
     * 刷新或续期access_token使用
     * access_token是调用授权关系接口的调用凭证，由于access_token有效期（目前为2个小时）较短，当access_token超时后，可以使用refresh_token进行刷新，access_token刷新结果有两种：
     *
     * 1. 若access_token已超时，那么进行refresh_token会获取一个新的access_token，新的超时时间；
     *
     * 2. 若access_token未超时，那么进行refresh_token不会改变access_token，但超时时间会刷新，相当于续期access_token。
     *
     * refresh_token拥有较长的有效期（30天），当refresh_token失效的后，需要用户重新授权，所以，请开发者在refresh_token即将过期时（如第29天时），进行定时的自动刷新并保存好它。
     * success return
     * {
     * "access_token":"ACCESS_TOKEN",
     * "expires_in":7200,
     * "refresh_token":"REFRESH_TOKEN",
     * "openid":"OPENID",
     * "scope":"SCOPE"
     * }
     * error return
     * {
     * "errcode":40030,"errmsg":"invalid refresh_token"
     * }
     * @param refresh_token 通过access_token获取到的refresh_token参数
     * @return
     */
    public String refreshToken(String refresh_token){
        String requestUrl = "https://api.weixin.qq.com/sns/oauth2/refresh_token?"
                + "appid=" + APP_ID
                + "&grant_type=refresh_token"
                + "&refresh_token=" + refresh_token;
        log.info("刷新access_token:URL-" + requestUrl);
        return HttpRequestUtils.send_get(requestUrl,null);
    }

    /**
     * 检验授权凭证（access_token）是否有效
     * success return
     * {
     * "errcode":0,"errmsg":"ok"
     * }
     * error return
     * {
     * "errcode":40003,"errmsg":"invalid openid"
     * }
     * @param access_token
     * @param openid
     */
    private String authAccessToken(String access_token,String openid){
        String requestUrl = "https://api.weixin.qq.com/sns/auth?"
                + "access_token=" + access_token
                + "&openid=" + openid;
        log.info("校验access_token:URL-" + requestUrl);
        return HttpRequestUtils.send_get(requestUrl,null);
    }

    /**
     * 获取用户个人信息（UnionID机制）
     * 此接口用于获取用户个人信息。
     * 开发者可通过OpenID来获取用户基本信息。特别需要注意的是，如果开发者拥有多个移动应用、网站应用和公众帐号，可通过获取用户基本信息中的unionid来区分用户的唯一性，
     * 因为只要是同一个微信开放平台帐号下的移动应用、网站应用和公众帐号，用户的unionid是唯一的。
     * 换句话说，同一用户，对同一个微信开放平台下的不同应用，unionid是相同的。
     * 请注意，在用户修改微信头像后，旧的微信头像URL将会失效，因此开发者应该自己在获取用户信息后，将头像图片保存下来，避免微信头像URL失效后的异常情况。
     * success return
     * {
     * "openid":"OPENID",
     * "nickname":"NICKNAME",
     * "sex":1,
     * "province":"PROVINCE",
     * "city":"CITY",
     * "country":"COUNTRY",
     * "headimgurl": "http://wx.qlogo.cn/mmopen/g3MonUZtNHkdmzicIlibx6iaFqAc56vxLSUfpb6n5WKSYVY0ChQKkiaJSgQ1dZuTOgvLLrhJbERQQ4eMsv84eavHiaiceqxibJxCfHe/0",
     * "privilege":[
     * "PRIVILEGE1",
     * "PRIVILEGE2"
     * ],
     * "unionid": " o6_bmasdasdsad6_2sgVt7hMZOPfL"
     * }
     * error return
     * {
     * "errcode":40003,"errmsg":"invalid openid"
     * }
     * @param access_token
     * @param openid
     * @return
     */
    private String getWeChatUserInfo(String access_token,String openid){
        String requestUrl = "https://api.weixin.qq.com/sns/userinfo?"
                + "access_token=" + access_token
                + "&openid=" + openid
                //国家地区语言版本，zh_CN 简体，zh_TW 繁体，en 英语，默认为zh-CN
                + "&&lang=zh_CN";
        log.info("获取用户信息:URL-" + requestUrl);
        return HttpRequestUtils.send_get(requestUrl, null);
    }

    /*****************************************************************************微信二维码登陆分割线*********************************************************************************************************/



    /******************************************************************************微信客服接口分割线*********************************************************************************************************/

    /**
     * 发送自定义消息
     * @param openID
     * @param messageData
     * @param type 消息类型 默认{@link com.naicha.wechat.wechat.enums.WeChatMessageType#TEXT}
     */
    @RequestMapping(value = "/sendMessage",method = RequestMethod.POST)
    public void sendMessage(String openID,Map<String,Object> messageData,String type){
        //TODO access_token需要从redis实时获取 保证有效期内获取可用的access_token 此处伪代码实现
        String access_token = "";
        String requestURL = "https://api.weixin.qq.com/cgi-bin/message/custom/send?access_token=" + access_token;
        String result = HttpRequestUtils.send_post(requestURL, null, DynamicMessageFactory.getMessageContent(openID,type,messageData), null);
        System.out.println(result);
    }

    /******************************************************************************微信客服接口分割线*********************************************************************************************************/
}
